package calc;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Stack;
import java.util.StringTokenizer;

public class Calculator {

	public static final int MAX_VALUE = 100000000;
	public static char[] CHAR_10_TO_TT = {'십','백','천','만'};
	public static char[] CHAR_TH_X_N = {'만','억'};
	public static char[] CHAR_0_TO_9 = {'영','일','이','삼','사','오','육','칠','팔','구'};

	public static void main(String[] args) throws IOException{
		Scanner scanner = new Scanner(System.in);

		while(true) {
			boolean isError = false;
			System.out.println("입력 예)이백 + {(-십만오백 + 만) - 1000}");
			System.out.println("입력)");
			String inputExp = scanner.nextLine();
			if (inputExp.compareTo("0") == 0) {
				scanner.close();
				break;
			}
			if (inputExp.replaceAll(" ", "").compareTo("") == 0) {
				System.out.println("입력된 식이 없습니다");
				continue;
			}

			if (inputExp.indexOf('+') == -1 && inputExp.indexOf('-') == -1) {
				System.out.println("피연자와 연산자 구성이 잘못되었습니다 -> " + inputExp);
				continue;
			}

			String[] checkUnit = inputExp.split(" ");

			if (checkUnit.length <= 1) {
				System.out.println("피연자와 연산자 구성이 잘못되었습니다 -> " + inputExp);
				continue;
			}

			for (int i = 0; i < checkUnit.length; i++) {
				if (Calculator.isOperator(checkUnit[i])) {
					if (i-1 > -1 && i+1 < checkUnit.length) {
						if (checkUnit[i-1].compareTo("+") == 0 && checkUnit[i+1].compareTo("+") == 0) {
							System.out.println("피연자와 연산자 구성이 잘못되었습니다 -> " + inputExp);
							isError = true;
							break;
						}
					}
				} else {
					if (i+1 < checkUnit.length && !Calculator.isOperator(checkUnit[+1])) {
						System.out.println("피연자와 연산자 구성이 잘못되었습니다 -> " + inputExp);
						isError = true;
						break;
					}
					if (checkUnit[i].indexOf('+') != -1) {
						System.out.println("피연자와 연산자 구성이 잘못되었습니다 -> " + inputExp);
						isError = true;
						break;
					}
				}
			}

			if(isError) {
				continue;
			} else {
				LinkedList<String> postFix = Calculator.changePostFix(inputExp);
				if (postFix == null) {
					System.out.println("유효한 식이 아닙니다 -> " + inputExp);
				} else {
					Result resultObj = Calculator.calculation(postFix);
					if (resultObj.errorMessage.compareTo("") == 0) {
						String hangeulResult = Calculator.getNumberToHangeul(resultObj.value);
						System.out.println("결과)" + hangeulResult);
					} else {
						System.out.println(resultObj.errorMessage);
					}
				}
			}
		}
	}

	public static boolean isOperator (String operator) {
		return (operator.compareTo("+") == 0 || operator.compareTo("-") == 0);
	}

	public static int getPrecedence(String operator) {
		if (operator.compareTo("+") == 0 || operator.compareTo("-") == 0) return 1;
		else return 0;
	}

	//후위연산
	public static Result calculation(LinkedList<String> postFix) {
		Stack<Integer> numberSaver = new Stack<Integer>();
		Result resultObj = new Result();
		while(!postFix.isEmpty()) {
			String t = postFix.pollFirst();
			if (!Calculator.isOperator(t)) {
				try {
					resultObj.value = Integer.parseInt(t);
					if (resultObj.value > Calculator.MAX_VALUE) {
						resultObj.errorMessage = "하나의 항목은 1억을 넘을 수 없습니다 -> " + resultObj.value;
						return resultObj;
					}
				} catch (NumberFormatException e) {
					resultObj = Calculator.getHangeulToNumber(t);
					if (resultObj.errorMessage.compareTo("") != 0) return resultObj;
				}
				numberSaver.push(resultObj.value);
			} else {
				int num1, num2;
				num1 = numberSaver.pop();
				num2 = numberSaver.pop();
				int tmp = 0;
				if (t.compareTo("+") == 0) {
					tmp = num1 + num2;
				} else {
					tmp = num2 - num1;
				}
				numberSaver.push(tmp);
			}
		}
		
		resultObj.value = numberSaver.pop(); 
		return resultObj;
	}

	//정수->한글 변환
	public static String getNumberToHangeul(int number) {
		String tmp = String.valueOf(Math.abs(number));
		StringBuffer buf = new StringBuffer(tmp);
		buf = buf.reverse();
		for (int i = 0; i <= tmp.length() / 4; i++) {
			buf.insert(i*5, ',');
		}
		buf.deleteCharAt(0);
		String[] divisions = buf.toString().split(",");
		StringBuffer strNumber = new StringBuffer();
		for (int i = 0; i < divisions.length; i++) {
			String section = divisions[i];
			for (int j = 0; j < section.length(); j++) {
				if(j > 0 && section.charAt(j) != '0') {
					strNumber.append(Calculator.CHAR_10_TO_TT[j-1]);
				}
				char c = section.charAt(j);
				if (c != '0' && c != '1') {
					strNumber.append(CHAR_0_TO_9[c-48]);
				}
			}
			if (i < divisions.length-1)
				strNumber.append(CHAR_TH_X_N[i]);
		}
		if (buf.charAt(0) == '1')
			strNumber.insert(0, '일');
		if (buf.length() == 1 && buf.charAt(0) == '0')
			strNumber.insert(0, '영');

		strNumber = strNumber.reverse();

		if (number < 0)
			strNumber.insert(0, '-');

		return strNumber.toString();
	}

	//중위표기->후위표기 변환
	public static LinkedList<String> changePostFix(String inputExp) {
		Stack<String> operatorSaver = new Stack<String>();
		LinkedList<String> postFix = new LinkedList<String>();
		boolean isError = false;
		StringTokenizer splitWhiteSpace = new StringTokenizer(inputExp, " ");
		while(splitWhiteSpace.hasMoreTokens()) {
			String section = splitWhiteSpace.nextToken();
			//연산자가 새로 들어오면
			if (Calculator.isOperator(section)) {
				operatorSaver.push(section);
			//연산자가 아닌 항목이 새로 들어오면 
			} else {
				StringBuffer sectionBuffer = new StringBuffer(section);
				try {
					while(true) {
						if(sectionBuffer.charAt(0) == '{') {
							operatorSaver.push("{");
							sectionBuffer.deleteCharAt(sectionBuffer.indexOf("{"));
						} else if(sectionBuffer.charAt(0) == '(') {
							operatorSaver.push("(");
							sectionBuffer.deleteCharAt(sectionBuffer.indexOf("("));
						} else if(sectionBuffer.charAt(0) == '[') {
							operatorSaver.push("[");
							sectionBuffer.deleteCharAt(sectionBuffer.indexOf("["));
						} else {
							StringTokenizer splitBraket = new StringTokenizer(sectionBuffer.toString(), "} ] )", true);
							while(splitBraket.hasMoreTokens()) {
								String elemental = splitBraket.nextToken();
								if (elemental.compareTo("}") == 0) {
									while (true) {
										if (operatorSaver.peek().compareTo("{") != 0) {
											postFix.offer(operatorSaver.pop());
										} else {
											operatorSaver.pop();
											break;
										}
									}
								} else if (elemental.compareTo("]") == 0) {
									while (true) {
										if (operatorSaver.peek().compareTo("[") != 0) {
											postFix.offer(operatorSaver.pop());
										} else {
											operatorSaver.pop();
											break;
										}
									}
								} else if (elemental.compareTo(")") == 0) {
									while (true) {
										if (operatorSaver.peek().compareTo("(") != 0) {
											System.out.println(operatorSaver.peek());
											postFix.offerLast(operatorSaver.pop());
										} else {
											operatorSaver.pop();
											break;
										}
									}
								} else {
									postFix.offer(elemental);
								}

							}
							break;
						}
					}
				} catch (Exception e) {
					isError = true;
					break;
				}
			}
		}
		
		//스택에 남아있는 연산자들을 다 꺼낸다 
		while(!operatorSaver.empty()) {
			String c = operatorSaver.pop();
			//괄호의 짝이 맞지 않으면 에러
			if (c.compareTo("{") == 0 || c.compareTo("(") == 0 || c.compareTo("[") == 0) {
				isError = true;
				break;
			}
			postFix.offerLast(c);
		}

		//연산자, 피연산자 개수 세기
		int vaild = 0;
		for(int i = 0; i < postFix.size(); i++) {
			if (Calculator.isOperator(postFix.get(i))) vaild++;
			else vaild--;
		}

		// 후위식 변환 후 항목의 개수가 피연산자가 연산자보다 1 적지 않으면 에러
		if (isError || vaild != -1) {
			return null;
		} else {
			return postFix;
		}
	}

	//한글 피연산자 -> 숫자 피연산자 변환
	public static Result getHangeulToNumber(String inputNumber) {
		StringBuffer str = new StringBuffer(inputNumber);
		Result resultObj = new Result();
		int sign = 1;
		if(str.charAt(0) == '-') {
			str = str.deleteCharAt(0);
			sign = -1;
		}
		if (str.indexOf("억") != -1 && str.length() > 2) {
			resultObj.errorMessage = "입력값이 잘못 되었거나 1억초과 입니다 -> " + str;
			return resultObj; 
		}
		if (str.indexOf("억") != -1) str.insert(str.indexOf("억")+1, ",");
		if (str.indexOf("만") != -1) str.insert(str.indexOf("만")+1, ",");
		//		System.out.println("시작:"+str);

		StringTokenizer nizer = new StringTokenizer(str.toString() , ",");
		int result = 0;
		while(nizer.hasMoreTokens()) {
			String token = nizer.nextToken();
			if (token.indexOf("억") != -1) {
				if (token.charAt(token.length()-1) != '억') {
					resultObj.errorMessage = "유효한 값이 아닙니다 -> " + token;
					return resultObj;
				}
				if (token.length() > 1 && token.charAt(0) != '일') {
					resultObj.errorMessage = "항목당 1억이하로 해야 합니다 -> " + token;
					return resultObj;
				} else {
					result = 100000000;
				}
			} else if (token.indexOf("만") != -1) {
				//								System.out.println("만단위:"+token);
				StringBuffer tmpToken = new StringBuffer(token);
				tmpToken.insert(tmpToken.indexOf("만"), ",");
				String[] subToken = tmpToken.toString().split(",");
				if (subToken[0].compareTo("") == 0 && subToken[1].compareTo("만") == 0) {
					result += 10000;
				} else if (subToken.length == 2) {
					resultObj = Calculator.getLessThousand(subToken[0]);
					if (resultObj.errorMessage.compareTo("") != 0) return resultObj;
					else result += resultObj.value * 10000;
				} else {
					resultObj.errorMessage = "잘못 입력하셨습니다 -> " + token;
					return resultObj;
				}
			} else {
				//								System.out.println("천단위:"+token);
				resultObj = Calculator.getLessThousand(token);
				if (resultObj.errorMessage.compareTo("") != 0) return resultObj;
				else result += resultObj.value;
			}
		}
		result *= sign;
		resultObj.value = result;
		return resultObj;
	}

	//10000미만의 한글피연산자 -> 숫자피연산자 변환 
	public static Result getLessThousand(String token) {
		StringBuffer tmpToken = new StringBuffer(token);
		if (tmpToken.indexOf("십") != -1) tmpToken.insert(tmpToken.indexOf("십")+1, ",");
		if (tmpToken.indexOf("백") != -1) tmpToken.insert(tmpToken.indexOf("백")+1, ",");
		if (tmpToken.indexOf("천") != -1) tmpToken.insert(tmpToken.indexOf("천")+1, ",");

		Result resultObj = new Result();
		StringTokenizer subNizer = new StringTokenizer(tmpToken.toString(), ",");
		int tmpResult, result;
		int prev, cur, cnt;
		prev = cur = cnt = tmpResult = result = 0;
		while(subNizer.hasMoreTokens()) {
			String subToken = subNizer.nextToken();
			if(subToken.length() == 2) {
				char[] subUnit = new char[2];
				subUnit[0] = subToken.charAt(0);
				subUnit[1] = subToken.charAt(1);
				int tmp0, tmp1;
				tmp0 = tmp1 = 0;
				for (int i = 0; i < Calculator.CHAR_0_TO_9.length; i++) {
					if (subUnit[0] == Calculator.CHAR_0_TO_9[i]) {
						tmp0 = i;
						break;
					}
				}

				for (int i = 0; i < Calculator.CHAR_10_TO_TT.length; i++) {
					if (subUnit[1] == Calculator.CHAR_10_TO_TT[i]) {
						tmp1 = (int) Math.pow(10, i+1);
						break;
					}
				}

				if (tmp0 * tmp1 > Calculator.MAX_VALUE) {
					resultObj.errorMessage = "하나의 항목은 1억을 넘을 수 없습니다 -> " + (tmp0*tmp1);
					return resultObj;
				} else {
					tmpResult = tmp0 * tmp1;
				}
			} else if(subToken.length() == 1) {
				for (int i = 0; i < Calculator.CHAR_10_TO_TT.length; i++) {
					if (subToken.charAt(0) == Calculator.CHAR_10_TO_TT[i]) {
						tmpResult = (int) Math.pow(10, i+1);
						break;
					}
				}
				for (int i = 0; i < Calculator.CHAR_0_TO_9.length; i++) {
					if (subToken.charAt(0) == Calculator.CHAR_0_TO_9[i]) {
						tmpResult = i;
						break;
					}
				}
			} else {
				resultObj.errorMessage = "유효한 값이 아닙니다 -> " + token;  
				return resultObj;
			}


			if (cnt > 0) cur = tmpResult;
			else prev = cur = tmpResult; 

			if (prev < cur) {
				resultObj.errorMessage = "유효한 값이 아닙니다 -> " + token;  
				return resultObj;
			}
			prev = cur;
			result += tmpResult;
			cnt++;			
		}
		resultObj.value = result;
		return resultObj;
	}
}
